package cn.itcast.zt.demo01;

import com.lmax.disruptor.RingBuffer;

import java.nio.ByteBuffer;

/**
 * 这是一个事件源，模拟的就是网络或者磁盘IO发送数据过来，触发事件
 * ByteBuffer中携带着数据
 * create by zhangtian3 on 2018/10/9
 */
public class StringEventProducer {
    private final RingBuffer<StringEvent> ringBuffer ;

    public StringEventProducer(RingBuffer<StringEvent> ringBuffer) {
        this.ringBuffer = ringBuffer ;
    }

    /**
     * 很明显的是：当用一个简单队列来发布事件的时候会牵涉更多的细节，这是因为事件对象还需要预先创建。
     * 发布事件最少需要两步：获取下一个事件槽并发布事件（发布事件的时候要使用try/finally保证事件一定会被发布）。
     * 如果我们使用RingBuffer.next()获取一个事件槽，那么一定要发布对应的事件。
     * 如果不能发布事件，那么就会引起Disruptor状态的混乱。
     * 尤其是在多个事件生产者的情况下会导致事件消费者失速，从而不得不重启应用才能会恢复。
     */
    public void sendData(ByteBuffer byteBuffer) {
        // ringBuffer就是用来存储数据的，具体可以看disruptor源码的数据结构，next就是获取下一个空事件索引
        long sequence = ringBuffer.next();
        try {
            // 通过索引获取空事件
            StringEvent stringEvent = ringBuffer.get(sequence);
            //切换成读模式
            byteBuffer.flip();
            // 从byteBuffer中读取传过来的值
            byte[] dst = new byte[byteBuffer.limit()];
            byteBuffer.get(dst, 0, dst.length);
            // 为stringEvent赋值，填充数据
            stringEvent.setValue(new String(dst));
            stringEvent.setId((int) sequence);
            // clear一下缓冲区
            byteBuffer.clear();
        } finally {
            //发布事件，为确保安全，放入finally中，不会造成disruptor的混乱
            ringBuffer.publish(sequence);
        }
    }
}
